import { css } from "@emotion/react"
import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react"

export interface BaseTakePhotoRef {
    startCamera: () => Promise<void>
    takePhoto: () => void
    restartCamera: () => void
}

export interface BaseTakePhotoProps {
    onCameraStart?: (success: boolean, error?: Error) => void
    onCaptureImage?: (imageData: string) => void
}

const BaseTakePhoto = forwardRef<BaseTakePhotoRef, BaseTakePhotoProps>(
    ({ onCameraStart, onCaptureImage }, ref) => {
        const videoRef = useRef<HTMLVideoElement | null>(null)
        const canvasRef = useRef<HTMLCanvasElement | null>(null)
        const [capturedImage, setCapturedImage] = useState<string | null>(null)

        // 開啟相機
        const startCamera = useCallback(async (): Promise<void> => {
            try {
                const stream = await navigator.mediaDevices.getUserMedia({
                    video: { facingMode: "user" }, // 使用自拍鏡頭
                    audio: false,
                })

                if (videoRef.current) {
                    videoRef.current.srcObject = stream
                }

                onCameraStart?.(true)
            } catch (err) {
                console.error("無法存取相機: ", err)
                onCameraStart?.(false, err instanceof Error ? err : new Error(String(err)))
            }
        }, [onCameraStart])

        // 拍照
        const takePhoto = useCallback((): void => {
            const video = videoRef.current
            const canvas = canvasRef.current

            if (video && canvas) {
                const ctx = canvas.getContext("2d")

                if (ctx) {
                    // 設置 canvas 大小與影片一致
                    canvas.width = video.videoWidth
                    canvas.height = video.videoHeight

                    // 繪製影像到 canvas
                    ctx.drawImage(video, 0, 0, canvas.width, canvas.height)

                    // 轉換為 base64 圖片
                    const imageData = canvas.toDataURL("image/png")
                    setCapturedImage(imageData)
                    onCaptureImage?.(imageData)

                    // 停止相機
                    const stream = video.srcObject as MediaStream
                    if (stream) {
                        stream.getTracks().forEach((track) => track.stop())
                    }
                }
            }
        }, [onCaptureImage])

        const restartCamera = useCallback(() => {
            setCapturedImage(null)
            startCamera()
        }, [startCamera])

        useImperativeHandle(ref, () => ({
            startCamera,
            takePhoto,
            restartCamera,
        }))

        useEffect(() => {
            startCamera()
            return () => {
                // 組件卸載時停止相機
                if (videoRef.current && videoRef.current.srcObject) {
                    const stream = videoRef.current.srcObject as MediaStream
                    stream.getTracks().forEach((track) => track.stop())
                }
            }
        }, [startCamera])

        return (
            <div
                css={css`
                    display: flex;
                    flex: 1;
                    flex-direction: column;
                    align-items: stretch;
                    justify-content: center;
                    height: 100%;
                `}
            >
                {!capturedImage ? (
                    <video
                        css={css`
                            height: 100%;
                            flex: 1;
                            object-fit: cover;
                            transform: scaleX(-1);
                        `}
                        ref={videoRef}
                        autoPlay
                        playsInline
                    />
                ) : (
                    <img
                        css={css`
                            height: 100%;
                            flex: 1;
                            object-fit: cover;
                            transform: scaleX(-1);
                        `}
                        src={capturedImage}
                        alt="自拍照"
                    />
                )}
                <canvas
                    ref={canvasRef}
                    style={{ display: "none" }}
                />
            </div>
        )
    },
)

BaseTakePhoto.displayName = "BaseTakePhoto"

export default BaseTakePhoto
